package com.talent.web.config.security;

import cn.hutool.core.util.StrUtil;
import com.talent.web.enums.ResponseEnum;
import com.talent.web.exception.TalentAuthenticationException;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * @ClassName：TokenAuthenticationFilter
 * @Author: hszhou
 * @Date: 2024/10/21 13:35
 * @Description: 过滤器
 */
@Component
@RequiredArgsConstructor
public class TokenAuthenticationFilter extends OncePerRequestFilter {
    private static final Logger logger = LoggerFactory.getLogger(TokenAuthenticationFilter.class);


    private  final JwtProvider jwtProvider;

    private  final AuthProperties authProperties;


    private final WhiteListProperties whiteListProperties;


    private void validate(HttpServletRequest request) {

        String authorization = request.getHeader( authProperties.getHeader());

        logger.error("[{}]",request.getRequestURI());

        if(StrUtil.isEmpty(authorization) || !StrUtil.startWith(authorization,authProperties.getPrefix()+" ")){
            logger.error("请求头中没有token[{}]",request.getRequestURI());
            throw new TalentAuthenticationException(ResponseEnum.UNAUTHORIZED);
        }
        String value = authorization.substring(7);
        TalentUserDetails userDetails=null;
        try {
            userDetails = jwtProvider.parseToken(value);
            //解析失败 过期
        }catch (Exception e){
            if(e instanceof SignatureException){
                throw new TalentAuthenticationException(ResponseEnum.INVALID_CREDENTIALS);
            }else if(e instanceof ExpiredJwtException){
                throw new TalentAuthenticationException(ResponseEnum.CERTIFICATION_EXPIRED);
            }else if(e instanceof MalformedJwtException){
                throw new TalentAuthenticationException(ResponseEnum.INVALID_CREDENTIALS);
            }
        }

        assert userDetails != null;
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
                null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String method = request.getMethod();

        if(method.equals(HttpMethod.GET.name())){
            if (whiteListProperties.getGets().stream().anyMatch(e->matchPath(e,request.getRequestURI()))) {
                filterChain.doFilter(request,response);
                return;
            }
        }
        if(method.equals(HttpMethod.POST.name())){
            if (whiteListProperties.getPosts().stream().anyMatch(e->matchPath(e,request.getRequestURI()))) {
                filterChain.doFilter(request,response);
                return;
            }
        }

        validate(request);
        filterChain.doFilter(request,response);
    }

    public  boolean matchPath(String configuredPath, String requestPath) {
        String patternString;
        // 处理 ** 的情况
        if (configuredPath.endsWith("/**")) {
            patternString = configuredPath.substring(0, configuredPath.length() - 3) + "(/.*)?";
        } else if (configuredPath.endsWith("/*")) {
            patternString = configuredPath.substring(0, configuredPath.length() - 2) + "/[^/]*";
        } else {
            patternString = configuredPath;
        }
        Pattern pattern = Pattern.compile(patternString);
        return pattern.matcher(requestPath).matches();
    }

}
